#include "pool.h"


//遗书
void *handler(void *arg)
{
    printf("[%zu]使用遗书\n",pthread_self());
    pthread_mutex_unlock((pthread_mutex_t *)arg);
}


//线程函数
void *routine(void *arg)
{
    thread_pool *pool = (thread_pool *) arg;
    struct task *p;

    while(1)
    {   
        //写遗书
        pthread_cleanup_push(handler, (void *)&pool->lock);     
        pthread_mutex_lock(&pool->lock);
        //待命
        while(pool->waiting_tasks == 0 && !pool->shutdown)      
        {
            pthread_cond_wait(&pool->cond, &pool->lock);
        }
        //销毁自己
        if(pool->waiting_tasks == 0 && pool->shutdown == true)          
        {
            pthread_mutex_unlock(&pool->lock);
            pthread_exit(NULL);
        }
        //执行任务
        p = pool->task_list->next;
        pool->task_list->next = p->next;
        pool->waiting_tasks--;
        //销毁遗书
        pthread_mutex_unlock(&pool->lock);
        pthread_cleanup_pop(0);
        //防止Cancel
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        (p->task)(p->arg);
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    }
    pthread_exit(NULL);
}


//初始化线程池
bool init_pool(thread_pool *pool, unsigned int threads_number)  
{
    pthread_mutex_init(&pool->lock, NULL);     //互斥锁初始化
    pthread_cond_init(&pool->cond, NULL);      //条件量初始化
    pool->shutdown = false;                    //线程池销毁标记初始化

    pool->task_list = malloc(sizeof(struct task));          //任务链队列指针初始化
    pool->tids = malloc(sizeof(pthread_t) * MAX_TIDS);      //最大线程数
    if(pool->task_list == NULL || pool->tids == NULL)
    {
        perror("分配内存出错");
        return false;
    }

    pool->task_list->next = NULL;
    pool->max_waiting_tasks = MAX_WAITING;
    pool->waiting_tasks =0;
    pool->active_threads = threads_number;

    for(int i=0; i<pool->active_threads; i++)
    {
        if(pthread_create(&((pool->tids)[i]), NULL, routine, (void *)pool) != 0)
        {
            perror("创建线程失败");
            return false;
        }        
    }

    return true;
}


//添加任务给线程执行
bool add_task(thread_pool *pool, void *(*mytask)(void *arg), void *arg)
{
    struct task *new_task = malloc(sizeof(struct task));//创建任务
    if(new_task == NULL)
	{
		perror("allocate memory error");
		return false;
	}
    new_task->arg = arg;
    new_task->next = NULL;
    new_task->task = mytask;

    pthread_mutex_lock(&pool->lock);//上锁添加任务

    if(pool->waiting_tasks > MAX_WAITING)//超出任务数限制
    {
        pthread_mutex_unlock(&pool->lock);
        fprintf(stderr,"超出任务数量\n");
        free(new_task);
        return false;
    }

    struct task *tmp = pool->task_list;//添加任务到链表
    while(tmp->next != NULL)
        tmp = tmp->next;
    tmp->next = new_task;
    pool->waiting_tasks++;

    pthread_mutex_unlock(&pool->lock);//解锁

    pthread_cond_signal(&pool->cond);//唤醒第一个睡眠等待的线程
    return true;
}